﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using UnityEngine.EventSystems;
using ET;
namespace UnityEngine.UI
{
    public class PEDText : Text, IPointerDownHandler
    {

 
        /// <summary>
        /// 超链接信息类
        /// </summary>
        private class HyperlinkInfo
        {
            public Color color;
            public int startIndex;

            public int endIndex;

            public string name;

            public readonly List<Rect> boxes = new List<Rect>();
#if UNITY_2019_1_OR_NEWER
            /// <summary>
            /// 顶点开始索引值
            /// </summary>
            public int NewStartIndex;

            /// <summary>
            /// 顶点结束索引值
            /// </summary>
            public int NewEndIndex;
#endif
        }

        /// <summary>
        /// 超链接正则
        /// 示例   请立即装备<a href=mujian>[木剑]</a>武器
        /// </summary>
        private static readonly Regex
            hrefRegex = new Regex(@"<a href=([^>\n\s]+)>(.*?)(</a>)", RegexOptions.Singleline);
        
        /// <summary>
        /// 解析完最终的文本
        /// </summary>
        private string outputText;

        /// <summary>
        /// 超链接信息列表
        /// </summary>
        private readonly List<HyperlinkInfo> hrefInfos = new List<HyperlinkInfo>();

        /// <summary>
        /// 文本构造器
        /// </summary>
        protected static readonly StringBuilder textBuilder = new StringBuilder();
        
        //计算定点信息的缓存数组
        private readonly UIVertex[] m_TempVerts = new UIVertex[4];

        /// <summary>
        /// 超链接点击事件
        /// </summary>
        private Action<string> OnHrefClick; //外界监听
        public void AddListener(Action<string> str)
        {
            OnHrefClick = str;
        }

        //private HyperlinkText mHyperlinkText;
        public string GetHyperlinkInfo
        {
            get { return text; }
        }

        public override void SetVerticesDirty()
        {
            base.SetVerticesDirty();

            text = GetHyperlinkInfo;
            outputText = GetOutputText(text);
        }

        /// <summary>
        /// 获取超链接解析后的最后输出文本
        /// </summary>
        /// <returns></returns>
        protected virtual string GetOutputText(string outputText)
        {
           
            textBuilder.Length = 0;
            hrefInfos.Clear();
            int indexText = 0;
            int newIndex = 0;
            string part = "";
            int colorLen = 24;
            foreach (Match match in hrefRegex.Matches(outputText))
            {
                textBuilder.Append(outputText.Substring(indexText, match.Index - indexText));
                part = textBuilder.ToString();

                int offset = 0;;
                if (match.Groups[2].Value.Contains("</color>"))
                {
                    offset = colorLen * 4;
                }

                var group = match.Groups[1];
                var hrefInfo = new HyperlinkInfo
                {
                    startIndex = textBuilder.Length * 4, // 超链接里的文本起始顶点索引
                    endIndex = (textBuilder.Length + match.Groups[2].Length - 1) * 4 + 3 - offset,//colorIdx * colorLen
                    name = group.Value,
                    color = textBuilder.ToString().ColorRich()
                    //color = color
                };
                // Log.Log(textBuilder.ToString() );
                hrefInfos.Add(hrefInfo);
                //textBuilder.Append("<color=#ff7200>");
                textBuilder.Append(match.Groups[2].Value);
                //textBuilder.Append("</color>");

#if UNITY_2019_1_OR_NEWER

                newIndex += ReplaceRichText(part).Length * 4;
                int newStartIndex = newIndex;
                newIndex += (match.Groups[2].Value.Length - 1) * 4 + 3;

                hrefInfo.NewStartIndex = newStartIndex;
                hrefInfo.NewEndIndex = newIndex - 1;
#endif
                indexText = match.Index + match.Length;
            }

            textBuilder.Append(outputText.Substring(indexText, outputText.Length - indexText));
            return textBuilder.ToString();
        }

        /// <summary>
        /// 画包围框
        /// </summary>
        /// <param name="toFill"></param>
        protected override void OnPopulateMesh(VertexHelper toFill)
        {
            var orignText = m_Text;

            m_Text = outputText;

            base.OnPopulateMesh(toFill);
            m_Text = orignText;
#if UNITY_2019_1_OR_NEWER
            bool autoLF = AutoLF();
#endif
            // 处理超链接包围框
            foreach (var hrefInfo in hrefInfos)
            {
                hrefInfo.boxes.Clear();
#if UNITY_2019_1_OR_NEWER
                int startIndex = autoLF ? hrefInfo.startIndex : hrefInfo.NewStartIndex;
                int endIndex = autoLF ? hrefInfo.endIndex : hrefInfo.NewEndIndex;
#else
                    int startIndex = hrefInfo.startIndex;
                    int endIndex = hrefInfo.endIndex;
#endif
                if (startIndex >= toFill.currentVertCount)
                {
                    continue;
                }

                UIVertex vert = new UIVertex();
                // 将超链接里面的文本顶点索引坐标加入到包围框
                toFill.PopulateUIVertex(ref vert, startIndex);
                var pos = vert.position;
                var bounds = new Bounds(pos, Vector3.zero);
                for (int i = startIndex, m = endIndex; i < m; i++)
                {
                    if (i >= toFill.currentVertCount)
                    {
                        break;
                    }

                    toFill.PopulateUIVertex(ref vert, i);
                    pos = vert.position;
                    if (pos.x < bounds.min.x) // 换行重新添加包围框pos.x <= bounds.min.x
                    {
                        hrefInfo.boxes.Add(new Rect(bounds.min, bounds.size));
                        bounds = new Bounds(pos, Vector3.zero);
                    }
                    else
                    {
                        bounds.Encapsulate(pos); // 扩展包围框
                    }
                }

                hrefInfo.boxes.Add(new Rect(bounds.min, bounds.size));
                
                //base.OnPopulateMesh(toFill);
            }

            //TODO 暂时屏蔽一下
            //添加下划线
            // Vector2 extents = rectTransform.rect.size;
            // var settings = GetGenerationSettings(extents);
            // TextGenerator underlineText = new TextGenerator();
            // underlineText.Populate("——", settings);
            // IList<UIVertex> tut = underlineText.verts;
            // for (int m = 0; m < hrefInfos.Count; m++)
            // {
            //     for (int i = 0; i < hrefInfos[m].boxes.Count; i++)
            //     {
            //         //计算下划线的位置
            //         Vector3[] ulPos = new Vector3[4];
            //         ulPos[0] = hrefInfos[m].boxes[i].position + new Vector2(-5f, fontSize * 0.01f);
            //         //GameObject.Find("a").transform.localPosition = ulPos[0];
            //         ulPos[1] = ulPos[0] + new Vector3(hrefInfos[m].boxes[i].width + 10, 0);
            //         //GameObject.Find("b").transform.localPosition = ulPos[1];
            //         ulPos[2] = hrefInfos[m].boxes[i].position + new Vector2(hrefInfos[m].boxes[i].width, 0) +
            //                    new Vector2(5, -2);
            //         ;
            //         //GameObject.Find("c").transform.localPosition = ulPos[2]+new Vector3(-5,-2,0);
            //         ulPos[3] = hrefInfos[m].boxes[i].position + new Vector2(-5, -2);
            //         //GameObject.Find("d").transform.localPosition = ulPos[3]+new Vector3(10,-2,0);;
            //
            //         //绘制下划线
            //         for (int j = 0; j < 4; j++)
            //         {
            //             m_TempVerts[j] = tut[j];
            //             m_TempVerts[j].color = hrefInfos[m].color;
            //             m_TempVerts[j].position = ulPos[j];
            //             if (j == 3)
            //                 toFill.AddUIVertexQuad(m_TempVerts);
            //         }
            //     }
            // }
        }

        //换掉富文本
        private string ReplaceRichText(string str)
        {
            //<size=10>text</size>
            str = Regex.Replace(str, @"<color=(.+?)>", "");
            str = Regex.Replace(str, @"<size=(.+?)>", "");
            str = str.Replace("</color>", "");
            str = str.Replace("<b>", "");
            str = str.Replace("</b>", "");
            str = str.Replace("<i>", "");
            str = str.Replace("</i>", "");
            str = str.Replace("\n", "");
            str = str.Replace("\t", "");
            str = str.Replace("\r", "");
            str = str.Replace(" ", "");
            str = str.Replace("\r", "");
            str = str.Replace("</size>", "");
            return str;
        }

        private bool AutoLF()
        {
            //width
            var settings = GetGenerationSettings(Vector2.zero);
            float width = cachedTextGeneratorForLayout.GetPreferredWidth(m_Text, settings) / pixelsPerUnit;
            bool widthResult = width <= rectTransform.sizeDelta.x || horizontalOverflow == HorizontalWrapMode.Overflow;
            //height
            settings = GetGenerationSettings(new Vector2(rectTransform.rect.size.x, 0.0f));
            float height = cachedTextGeneratorForLayout.GetPreferredHeight(m_Text, settings) / pixelsPerUnit;
            bool heightResult = height <= rectTransform.sizeDelta.y || verticalOverflow == VerticalWrapMode.Overflow;
            return !widthResult || !heightResult;
        }

        public void OnPointerDown(PointerEventData eventData)
        {
            Vector2 lp = Vector2.zero;
            RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, eventData.position,
                eventData.pressEventCamera, out lp);

            foreach (var hrefInfo in hrefInfos)
            {
                var boxes = hrefInfo.boxes;
                for (var i = 0; i < boxes.Count; ++i)
                {
                    if (boxes[i].Contains(lp))
                    {
                        OnHrefClick?.Invoke(hrefInfo.name);
                        return;
                    }
                }
            }
        }
    }
}